using System;
using System.Runtime.InteropServices;
using EnvDTE;
using System.Windows.Forms;
using System.IO;
using System.Collections;
using System.Collections.Generic;

using ClassBuilderWizard.Interfaces;

using Microsoft.VisualStudio.TemplateWizard;
using Microsoft.Win32;

namespace ClassBuilderWizard
{
    /// <summary>
    /// The primary class that displays the wizard interface within the Visual Studio environment
    /// </summary>
    [GuidAttribute("996EC87A-E837-461C-8BFC-BDAEA8B76F3C")]
    public class ClassBuilder : IDTWizard, IWizard
    {
        private Parameters _PluginParameters;

        public ClassBuilder()
        {
        }

        #region IDTWizard Members

        public void Execute(object Application, int hwndOwner, ref object[] ContextParams, ref object[] CustomParams, ref EnvDTE.wizardResult retval)
        {
            /* ContextParams index catalog:
             * 0 = Wizard Type          string
             * 1 = Project name         string
             * 2 = Project Items        ProjectItems
             * 3 = Local Folder         string
             * 4 = New Item's filename  string
             * 5 = VS install path      string
             * 6 = Is Silent Mode       bool
             */

            //put together the parameters to pass to a plugin
            Parameters prms = new Parameters();
            prms.IDEWizardType = (string)ContextParams[0];
            prms.ProjectName = (string)ContextParams[1];
            prms.IDEProjectItems = (ProjectItems)ContextParams[2];
            prms.IDEProject = (ContextParams[2] as ProjectItems).ContainingProject;
            prms.ProjectNamespace = prms.IDEProject.Properties.Item("RootNamespace").Value.ToString();
            string filename = (string)ContextParams[4];
            prms.CurrentProjectType = (filename.EndsWith(".vb")) ? ProjectType.VB : ProjectType.CSharp;
            prms.NewItemName = (filename.EndsWith(".cs") || filename.EndsWith(".vb")) ? filename.Substring(0, filename.Length - 3) : filename;
            prms.IDEInstallPath = (string)ContextParams[5];
            prms.IDEApplication = (_DTE)Application;

            this._PluginParameters = prms;

            //make sure the wizard is running in the "Add an Item" mode
            if (this._PluginParameters.IDEWizardType != EnvDTE.Constants.vsWizardAddItem)
            {
                MessageBox.Show("This wizard can only be used from within the Add Item context.");
            }
            else
            {
                StartWizard();
            }
        }
        #endregion

        #region Wizard Interface
        /// <summary>
        /// Start the wizard
        /// </summary>
        private void StartWizard()
        {
            frmStartWizard frmStart = new frmStartWizard();
            if (frmStart.ShowDialog() == DialogResult.OK)
            {
                Plugin p = frmStart.SelectedPlugin;
                if (p.PluginType == PluginType.Database)
                {
                    IDatabasePlugin idbp = (IDatabasePlugin)p.PluginInterface;
                    DatabaseObject dbo = idbp.ExecutePlugin(this._PluginParameters);

                    if (dbo.Columns != null && dbo.Columns.Count > 0)
                    {
                        //we're ready to create the entity object
                        EntityBuilder eb = new EntityBuilder(dbo, this._PluginParameters);
                        CreateEntityClassFile(eb.GetEntityClassBody());

                        if (this._PluginParameters.CreateDAL)
                        {
                            //DALBuilder db = new DALBuilder(dbo, this._PluginParameters);
                            //CreateDALClassFile(db.GetDALClassBody());
                            CreateDALClassFile(dbo.DataAccessClassDefinition);

                            if (!string.IsNullOrEmpty(dbo.ScriptDefinition))
                            {
                                ScriptBuilder sb = new ScriptBuilder(dbo, this._PluginParameters);
                                CreateScriptFile(sb.GetScriptBody());
                            }
                        }
                    }
                }
                else if (p.PluginType == PluginType.Manual)
                {
                    IManualPlugin imp = (IManualPlugin)p.PluginInterface;
                    ManualObject mo = imp.ExecutePlugin(this._PluginParameters);

                    if (mo.Properties != null && mo.Properties.Count > 0)
                    {
                        //we're ready to create the entity object
                        EntityBuilder eb = new EntityBuilder(mo, this._PluginParameters);
                        CreateEntityClassFile(eb.GetEntityClassBody());
                    }
                }
            }
            frmStart.Dispose();
        }
        #endregion

        #region Class File Generation
        private void CreateEntityClassFile(string contents)
        {
            Common.CreateFileFromTemplate(contents, this._PluginParameters, "file1", this._PluginParameters.NewItemName);
        }
        private void CreateDALClassFile(string contents)
        {
            Common.CreateFileFromTemplate(contents, this._PluginParameters, "file2", this._PluginParameters.NewItemName + "DataAccess");
        }
        private void CreateScriptFile(string contents)
        {
            Common.CreateFileFromTemplate(contents, this._PluginParameters, "script", this._PluginParameters.NewItemName);
        }
        #endregion

        #region IWizard Members
        public void BeforeOpeningFile(ProjectItem projectItem)
        {
        }

        public void ProjectFinishedGenerating(Project project)
        {
        }

        public void ProjectItemFinishedGenerating(ProjectItem projectItem)
        {
        }

        public void RunFinished()
        {
        }

        public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
        {
            if (runKind == WizardRunKind.AsNewItem)
            {
                EnvDTE._DTE ide = (EnvDTE._DTE)automationObject;
                EnvDTE.Project project = GetActiveProject(ide);
                if (project != null)
                {
                    Parameters prms = new Parameters();
                    prms.ProjectName = project.Name;
                    prms.IDEProjectItems = project.ProjectItems;
                    prms.IDEProject = project;
                    prms.IDEWizardType = EnvDTE.Constants.vsWizardAddItem;
                    try
                    {
                        prms.ProjectNamespace = prms.IDEProject.Properties.Item("RootNamespace").Value.ToString();
                    }
                    catch (System.ArgumentException)
                    {
                        //the project doesn't have a root namespace property
                        prms.ProjectNamespace = string.Empty;
                    }
                    string filename = replacementsDictionary["$rootname$"];
                    prms.CurrentProjectType = (filename.EndsWith(".vb")) ? ProjectType.VB : ProjectType.CSharp;
                    prms.NewItemName = (filename.EndsWith(".cs") || filename.EndsWith(".vb")) ? filename.Substring(0, filename.Length - 3) : filename;
                    prms.IDEInstallPath = RegistryHelper.GetVSInstallPathFromRegistry(ide.RegistryRoot);
                    prms.IDEApplication = ide;
                    
                    this._PluginParameters = prms;
                    StartWizard();
                }
            }
        }

        public bool ShouldAddProjectItem(string filePath)
        {
            return false;
        }
        #endregion

        #region Helper methods for IWizard implementation
        private EnvDTE.Project GetActiveProject(EnvDTE._DTE ide)
        {
            EnvDTE.Project result = null;
            Array projects = ide.ActiveSolutionProjects as Array;

            if (projects != null && projects.Length > 0)
            {
                result = projects.GetValue(0) as EnvDTE.Project;
            }

            return result;
        }
        #endregion
    }
}
